package tdomhan.addict.dictionary;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Vector;

import com.ibm.icu.text.Collator;

import tdomhan.addict.parser.StringCollatorComparator;
import tdomhan.addict.parser.Translation;
import tdomhan.addict.parser.Translation.TranslationDirection;

/**
 * Class representing a dictionary.
 * can be written to or read from a file.
 * @author tobi
 *
 */
public class Dictionary {
	
	Vector<String> uniqueFirstLangWords = null;
	Vector<String> uniqueSecondLangWords = null;
	Vector<Translation> firstLangTranslations = null;
	Vector<Translation> secondLangTranslations = null;
	int[] firstLangAppearIdx = null;
	int[] secondLangAppearIdx = null;
	
	Collator firstLangCollator;
	Collator secondLangCollator;
	
	private final int FILE_VERSION = 1;
	
	public Dictionary(Collator firstLangCollator, Collator secondLangCollator) {
		this.firstLangCollator = firstLangCollator;
		this.secondLangCollator = secondLangCollator;
	}

	public void writeTo(BufferedWriter out) throws IOException {
		if(		uniqueFirstLangWords == null
				||uniqueSecondLangWords == null
				|| firstLangTranslations == null
				|| secondLangTranslations == null
				|| firstLangAppearIdx == null
				|| secondLangAppearIdx == null)
			throw new IOException("not all attributes set");
		//write out the file version
		out.write(Integer.toString(FILE_VERSION));
		out.newLine();
		
		//write out the size of all data structures:
		out.write(Integer.toString(uniqueFirstLangWords.size()));
		out.newLine();
		out.write(Integer.toString(uniqueSecondLangWords.size()));
		out.newLine();
		out.write(Integer.toString(firstLangTranslations.size()));
		out.newLine();
		out.write(Integer.toString(secondLangTranslations.size()));
		out.newLine();
		out.write(Integer.toString(firstLangAppearIdx.length));
		out.newLine();
		out.write(Integer.toString(secondLangAppearIdx.length));
		out.newLine();
		
		//write out the actual data:
		for (String word : uniqueFirstLangWords) {
			out.write(word);
			out.newLine();
		}
		for (String word : uniqueSecondLangWords) {
			out.write(word);
			out.newLine();
		}
		for (Translation translation : firstLangTranslations) {
			translation.writeTo(out);
		}
		for (Translation translation : secondLangTranslations) {
			translation.writeTo(out);
		}
		for (int idx : firstLangAppearIdx) {
			out.write(Integer.toString(idx));
			out.newLine();
		}
		for (int idx : secondLangAppearIdx) {
			out.write(Integer.toString(idx));
			out.newLine();
		}
		out.close();
	}
	
	public void readFrom(BufferedReader in) throws IOException {
		if(Integer.parseInt(in.readLine()) != FILE_VERSION) {
			throw new IOException("unsupported file version");
		}
		int numFirstLangWords = Integer.parseInt(in.readLine());
		int numSecondLangWords = Integer.parseInt(in.readLine());
		int numFirstTranslations = Integer.parseInt(in.readLine());
		int numSecondTranslations = Integer.parseInt(in.readLine());
		int numFirstLangIdx = Integer.parseInt(in.readLine());
		int numSecondLangIdx = Integer.parseInt(in.readLine());
		//read the unique words:
		uniqueFirstLangWords = new Vector<String>();
		uniqueFirstLangWords.setSize(numFirstLangWords);
		for (int i = 0; i < numFirstLangWords; i++) {
			uniqueFirstLangWords.set(i,in.readLine());
		}
		uniqueSecondLangWords = new Vector<String>();
		uniqueSecondLangWords.setSize(numSecondLangWords);
		for (int i = 0; i < numSecondLangWords; i++) {
			uniqueSecondLangWords.set(i,in.readLine());
		}
		//read the translations:
		firstLangTranslations = new Vector<Translation>();
		firstLangTranslations.setSize(numFirstTranslations);
		for (int i = 0; i < numFirstTranslations; i++) {
			Translation trans = new Translation();
			trans.readFrom(in);
			firstLangTranslations.set(i,trans);
		}
		
		secondLangTranslations = new Vector<Translation>();
		secondLangTranslations.setSize(numSecondTranslations);
		for (int i = 0; i < numSecondTranslations; i++) {
			Translation trans = new Translation();
			trans.readFrom(in);
			secondLangTranslations.set(i,trans);
		}
		//read the indices:
		firstLangAppearIdx = new int[numFirstLangIdx];
		for (int i = 0; i < numFirstLangIdx; i++) {
			firstLangAppearIdx[i] = Integer.parseInt(in.readLine());
		}
		secondLangAppearIdx = new int[numSecondLangIdx];
		for (int i = 0; i < numSecondLangIdx; i++) {
			secondLangAppearIdx[i] = Integer.parseInt(in.readLine());
		}
		//done
	}
	
	/**
	 * Constructs this dictionary from a list of translations.
	 * @param translations of the first language, will be used internally, don't change it after calling this method
	 */
	public void constructFromTranslations(Vector<Translation> translations) {
		firstLangTranslations = translations;
		
		HashMap<String, Integer> uniqueFirstLangWordsMap = new HashMap<String, Integer>();
		HashMap<String, Integer> uniqueSecondLangWordsMap = new HashMap<String, Integer>();
		
		//sort the english translations:
		Translation.setTranslationDirection(TranslationDirection.FIRST_SECOND_LANGUAGE);
		Collections.sort(firstLangTranslations);
		
		secondLangTranslations = new Vector<Translation>();
		for (int i=0;i<firstLangTranslations.size();i++) {
			Translation translation = translations.get(i);
			 // fill the vector that will contain the same translations but sorted by the finnish values
			secondLangTranslations.add(translation);
			String s = translation.getFirstLanguage();
			if(!uniqueFirstLangWordsMap.containsKey(s))
				uniqueFirstLangWordsMap.put(s, i);
		}
		
		//also sort the finnish translations
		Translation.setTranslationDirection(TranslationDirection.SECOND_FIRST_LANGUAGE);
		Collections.sort(secondLangTranslations);
		
		for (int i=0;i<secondLangTranslations.size();i++) {
			Translation translation = secondLangTranslations.get(i);
			String s = translation.getSecondLanguage();
			if(!uniqueSecondLangWordsMap.containsKey(s))
				uniqueSecondLangWordsMap.put(s, i);
		}			
		
		uniqueFirstLangWords  = new Vector<String>(uniqueFirstLangWordsMap.keySet());
		uniqueSecondLangWords  = new Vector<String>(uniqueSecondLangWordsMap.keySet());
		Collections.sort(uniqueFirstLangWords, new StringCollatorComparator(firstLangCollator));
		Collections.sort(uniqueSecondLangWords, new StringCollatorComparator(secondLangCollator));
		Translation.setUniqueFirstLangWords(uniqueFirstLangWords);
		Translation.setUniqueSecondLangWords(uniqueSecondLangWords);
		
		//fill the array of indices:
		firstLangAppearIdx = new int[uniqueFirstLangWords.size()];
		for (int i=0;i<uniqueFirstLangWords.size();i++) {
			String word = uniqueFirstLangWords.get(i);
			firstLangAppearIdx[i] = uniqueFirstLangWordsMap.get(word);
		}
		Translation.setFirstLangAppearIdx(firstLangAppearIdx);
		
		secondLangAppearIdx = new int[uniqueSecondLangWords.size()];
		for (int i=0;i<uniqueSecondLangWords.size();i++) {
			String word = uniqueSecondLangWords.get(i);
			secondLangAppearIdx[i] = uniqueSecondLangWordsMap.get(word);
		}
		Translation.setSecondLangAppearIdx(secondLangAppearIdx);
		
		for (Translation translation : translations) {
			translation.createStaticWordReference();
		}	
	}
	
	/**
	 * @return the uniqueSecondLangWords
	 */
	public Vector<String> getUniqueSecondLangWords() {
		return uniqueSecondLangWords;
	}

	/**
	 * @param uniqueSecondLangWords the uniqueSecondLangWords to set
	 */
	public void setUniqueSecondLangWords(Vector<String> uniqueSecondLangWords) {
		this.uniqueSecondLangWords = uniqueSecondLangWords;
	}

	

	/**
	 * @return the uniqueFirstLangWords
	 */
	public Vector<String> getUniqueFirstLangWords() {
		return uniqueFirstLangWords;
	}

	/**
	 * @param uniqueFirstLangWords the uniqueFirstLangWords to set
	 */
	public void setUniqueFirstLangWords(Vector<String> uniqueFirstLangWords) {
		this.uniqueFirstLangWords = uniqueFirstLangWords;
	}
	/**
	 * @return the firstLangTranslations
	 */
	public Vector<Translation> getFirstLangTranslations() {
		return firstLangTranslations;
	}

	/**
	 * @param firstLangTranslations the firstLangTranslations to set
	 */
	public void setFirstLangTranslations(Vector<Translation> firstLangTranslations) {
		this.firstLangTranslations = firstLangTranslations;
	}

	/**
	 * @return the secondLangTranslations
	 */
	public Vector<Translation> getSecondLangTranslations() {
		return secondLangTranslations;
	}

	/**
	 * @param secondLangTranslations the secondLangTranslations to set
	 */
	public void setSecondLangTranslations(Vector<Translation> secondLangTranslations) {
		this.secondLangTranslations = secondLangTranslations;
	}

	/**
	 * @return the firstLangAppearIdx
	 */
	public int[] getFirstLangAppearIdx() {
		return firstLangAppearIdx;
	}

	/**
	 * @param firstLangAppearIdx the firstLangAppearIdx to set
	 */
	public void setFirstLangAppearIdx(int[] firstLangAppearIdx) {
		this.firstLangAppearIdx = firstLangAppearIdx;
	}

	/**
	 * @return the secondLangAppearIdx
	 */
	public int[] getSecondLangAppearIdx() {
		return secondLangAppearIdx;
	}

	/**
	 * @param secondLangAppearIdx the secondLangAppearIdx to set
	 */
	public void setSecondLangAppearIdx(int[] secondLangAppearIdx) {
		this.secondLangAppearIdx = secondLangAppearIdx;
	}
	
	
	
}
